package com.ruoyi.web.controller.supconauth;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;

public class DesUtil {
	private static final Logger log = LoggerFactory.getLogger(DesUtil.class);

	// 定义字符集
	private static final String ENCODING = "UTF-8";

	/**
	 * 根据提供的密钥生成AES专用密钥
	 *
	 * @param password 可以是中文、英文、16进制字符串
	 * @return AES密钥
	 * @throws Exception
	 * @explain
	 */
	public static byte[] generateKey(String password) throws Exception {
		byte[] keyByteArray = null;
		// 创建AES的Key生产者
		KeyGenerator kgen = KeyGenerator.getInstance("AES");
		// 利用用户密码作为随机数初始化
		// 128位的key生产者
		// 加密没关系，SecureRandom是生成安全随机数序列，password.getBytes()是种子，只要种子相同，序列就一样，所以解密只要有password就行
		/*
		 * 只适用windows
		 * kgen.init(128, new SecureRandom(password.getBytes(ENCODING)));
		 */
		// 指定强随机数的生成方式
		// 兼容linux
		SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
		random.setSeed(password.getBytes(ENCODING));
		kgen.init(128, random);// 只能是128位

		// 根据用户密码，生成一个密钥
		SecretKey secretKey = kgen.generateKey();
		// 返回基本编码格式的密钥，如果此密钥不支持编码，则返回null。
		keyByteArray = secretKey.getEncoded();
		return keyByteArray;
	}

	/**
	 * AES加密字符串
	 *
	 * @param content  需要被加密的字符串
	 * @param password 加密需要的密码
	 * @return 16进制的密文（密文的长度随着待加密字符串的长度变化而变化，至少32位）
	 */
	public static String encrypt(String content, String password) {
		String cipherHexString = "";// 返回字符串
		try {
			// 转换为AES专用密钥
			byte[] keyBytes = generateKey(password);

			SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
			// 将待加密字符串转二进制
			byte[] clearTextBytes = content.getBytes(ENCODING);
			// 创建密码器
			Cipher cipher = Cipher.getInstance("AES");
			// 初始化为加密模式的密码器
			cipher.init(Cipher.ENCRYPT_MODE, sks);
			// 加密结果
			byte[] cipherTextBytes = cipher.doFinal(clearTextBytes);
			// byte[]-->hexString
			cipherHexString = Base64.getEncoder().encodeToString(cipherTextBytes);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("AES加密失败：" + e.getMessage());
		}
		return cipherHexString;
	}

	/**
	 * 解密AES加密过的字符串
	 *
	 * @param cipherText  aes base64密文
	 * @param password 加密时的密码
	 * @return 明文
	 */
	public static String decrypt(String cipherText, String password) {
		String clearText = "";
		try {
			// 转换为AES专用密钥
			byte[] keyBytes = generateKey(password);

			SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
			// 创建密码器
			Cipher cipher = Cipher.getInstance("AES");
			// 初始化为解密模式的密码器
			cipher.init(Cipher.DECRYPT_MODE, sks);
			// cipherText-->byte[]
			// 将16进制密文转换成二进制
			byte[] cipherTextBytes =  Base64.getDecoder().decode(cipherText);
			// 解密结果
			byte[] clearTextBytes = cipher.doFinal(cipherTextBytes);
			// byte[]-->String
			clearText = new String(clearTextBytes, ENCODING);
		} catch (Exception e) {
			log.error("AES解密失败：" + e.getMessage());
		}
		return clearText;
	}


	/**
	 * AES加密字符串
	 *
	 * @param content  需要被加密的字符串
	 * @param password 加密需要的密码
	 * @return 16进制的密文（密文的长度随着待加密字符串的长度变化而变化，至少32位）
	 */
	public static byte[] encryptByte(byte[] clearTextBytes, String password) {
		try {
			// 转换为AES专用密钥
			byte[] keyBytes = generateKey(password);

			SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
			// 将待加密字符串转二进制
			// 创建密码器
			Cipher cipher = Cipher.getInstance("AES");
			// 初始化为加密模式的密码器
			cipher.init(Cipher.ENCRYPT_MODE, sks);
			// 加密结果
			byte[] cipherTextBytes = cipher.doFinal(clearTextBytes);
			// byte[]-->hexString
			return cipherTextBytes;
		} catch (Exception e) {
			e.printStackTrace();
			log.error("AES加密失败：" + e.getMessage());
		}
		return null;
	}

	/**
	 * 解密AES加密过的字符串
	 *
	 * @param cipherText  aes base64密文
	 * @param password 加密时的密码
	 * @return 明文
	 */
	public static byte[] decryptByte(byte[] cipherTextBytes, String password) {
		try {
			// 转换为AES专用密钥
			byte[] keyBytes = generateKey(password);

			SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
			// 创建密码器
			Cipher cipher = Cipher.getInstance("AES");
			// 初始化为解密模式的密码器
			cipher.init(Cipher.DECRYPT_MODE, sks);
			// cipherText-->byte[]
			// 将16进制密文转换成二进制
			// 解密结果
			byte[] clearTextBytes = cipher.doFinal(cipherTextBytes);
			return clearTextBytes;
		} catch (Exception e) {
			log.error("AES解密失败：" + e.getMessage());
		}
		return null;
	}
}
